#include "guish.hpp"

Environment::Environment()
{
	numVars = 0;
	for(char **pos=environ; *pos; pos++)
		numVars++;
	
	varsAlloc = numVars;
	vars = (char**)calloc(varsAlloc+1, sizeof(char*));
	
	for(int ii=0; environ[ii]; ii++) {
		vars[ii] = strdup(environ[ii]);
		string varname = extractKey(environ[ii]);
		index[varname] = ii;
	}
}

Environment::Environment(const Environment &copy)
{
	const char *const *copyVars = copy.c_strs();
	
	numVars = 0;
	for(const char *const *pos=copyVars; *pos; pos++)
		numVars++;
	
	varsAlloc = numVars;
	vars = (char**)calloc(varsAlloc+1, sizeof(char*));
	
	for(int ii=0; copyVars[ii]; ii++) {
		vars[ii] = strdup(copyVars[ii]);
		string varname = extractKey(copyVars[ii]);
		index[varname] = ii;
	}
}

Environment::~Environment()
{
	for(int ii=0; ii<numVars; ii++)
		free(vars[ii]);
	free(vars);
}

char **Environment::c_strs()
	{ return vars; }
const char *const *Environment::c_strs() const
	{ return vars; }

void Environment::set(string name, string value)
{
	char *str = (char*)malloc(name.length() + value.length() + 2);
	strcpy(str, name.c_str());
	strcat(str, "=");
	strcat(str, value.c_str());
	
	map<string, int>::iterator it = index.find(name);
	if(it == index.end()) {
		if(numVars+1 >= varsAlloc) {
			varsAlloc += 16;
			vars = (char**)realloc(vars, (varsAlloc+1)*sizeof(char*));
		}
		vars[numVars++] = str;
		vars[numVars] = NULL;
	} else {
		int varIndex = it->second;
		free(vars[varIndex]);
		vars[varIndex] = str;
	}
}

string Environment::get(string name) const
{
	map<string, int>::const_iterator it = index.find(name);
	if(it!=index.end()) {
		int varIndex = it->second;
		return extractValue(vars[varIndex]);
	} else
		return "";
}

string extractKey(const char *str)
{
	for(int ii=0; str[ii]; ii++)
	{
		if(str[ii]=='=')
			return string(str, ii);
	}
	
	return "";
}

string extractValue(const char *str)
{
	for(int ii=0; str[ii]; ii++)
	{
		if(str[ii]=='=')
			return string(str+ii+1);
	}
	
	return string(str);
}

BUILTIN(setenv, "setenv")
{
	if(argv.size() <= 1) {
		// TODO: Output a listing of all evironment variables
		return 0;
	}
	
	if(argv.size() > 3) {
		job->reportError("setenv: Too many arguments.");
		return 1;
	}
	
	string varname = argv[1];
	string value = "";
	if(argv.size() == 3)
		value = argv[2];
	
	job->getState()->env.set(varname, value);
	return 0;
}

BUILTIN(exportVar, "export")
{
	if(argv.size() <= 1) {
		// TODO: Output a listing of all environment variables
		return 0;
	}
	
	// TODO: If the first argument is -n, that means un-export
	
	for(size_t ii=1; ii<argv.size(); ii++)
	{
		string key = extractKey(argv[ii].c_str());
		string val = extractValue(argv[ii].c_str());
		
		if(key!="") {
			job->getState()->env.set(key, val);
		}
		// TODO: Set the 'exported' flag
	}
	return 0;
}

